#!/bin/bash
# Usage:
# apply|flow|offload|rx_buffer|tx_buffer|vm_dirty|vm_background|current_user_watches|max_user_watches|cpu_freq_driver|cpu_governor|set_governor|turbo_mode|save_syslog|remove_syslog|get_nics.
#

apply_tweaks()
{
	OIFS=$IFS
	IFS=","
	list=($ETHERNET_NICS)
	for ((i=0; i<${#list[@]}; ++i)); do
		nic=${list[$i]}

		if [ "$FLOW_CONTROL" != "default" ]; then
			if [ "$FLOW_CONTROL" = "yes" ]; then
				/usr/sbin/ethtool -A $nic autoneg off rx off tx off &>/dev/null
			else
				/usr/sbin/ethtool -A $nic autoneg on rx on tx on &>/dev/null
			fi
			sleep 0.25
		fi

		if [ "$TSO_OFFLOAD" != "default" ]; then
			if [ "$TSO_OFFLOAD" = "yes" ]; then
				/usr/sbin/ethtool -K $nic gso off gro off tso off &>/dev/null
			else
				/usr/sbin/ethtool -K $nic gso on gro on tso on &>/dev/null
			fi
			sleep 0.25
		fi

		if [ "$RX_BUFFER" != "default" ]; then
			/usr/sbin/ethtool -G $nic rx "$RX_BUFFER" &>/dev/null 
		fi
		if [ "$TX_BUFFER" != "default" ]; then
			/usr/sbin/ethtool -G $nic tx "$TX_BUFFER" &>/dev/null
		fi
		sleep 0.25
	done

	# Disk cache settings.
	if [ "$VM_DIRTY" = "" ]; then
		sysctl -qw vm.dirty_ratio="20" &>/dev/null
	else
		sysctl -qw vm.dirty_ratio="$VM_DIRTY" &>/dev/null
	fi
	if [ "$VM_BACKGROUND" = "" ];then
		sysctl -qw vm.dirty_background_ratio="10" &>/dev/null
	else
		sysctl -qw vm.dirty_background_ratio="$VM_BACKGROUND" &>/dev/null
	fi

	# Set the inotify max_user_watches.
	if [ "$MAX_WATCHES" = "" ]; then
		# Set the inotify max_user_watches.
		sysctl -qw fs.inotify.max_user_watches="524288" > /dev/null
	else
		# Set the inotify max_user_watches.
		sysctl -qw fs.inotify.max_user_watches="$MAX_WATCHES" > /dev/null
	fi

	# Set the ulimit.
	if [ "$MAX_OPEN_FILES" = "" ]; then
		# Set default ulimit.
		ulimit -n 40960
	else
		max_files=$(($MAX_OPEN_FILES))
		if [ $max_files -lt 40960 ]; then
			max_files=40960
		fi
		if [ $max_files -gt 65535 ]; then
			max_files=65535
		fi
		# Set new ulimit.
		ulimit -n $max_files
	fi

	# Restart samba
	/etc/rc.d/rc.samba restart &>/dev/null

	if [ "$SCHEDULED" = "yes" ]; then
		IFS=":"
		list=($START_TIME)
		printf "# Set cpu governor to power saving mode:\n" > /boot/config/plugins/dynamix/cpu_governor.cron
		printf "${list[1]} ${list[0]} * * * ${DOCROOT}/plugins/${plugin}/scripts/rc.tweaks set_governor ${POWER_SAVE_CPU_GOVERNOR} &> /dev/null\n\n" >> /boot/config/plugins/dynamix/cpu_governor.cron
		list=($STOP_TIME)
		printf "# Set cpu governor to normal mode:\n" >> /boot/config/plugins/dynamix/cpu_governor.cron
		printf "${list[1]} ${list[0]} * * * ${DOCROOT}/plugins/${plugin}/scripts/rc.tweaks set_governor ${CPU_GOVERNOR} &> /dev/null\n\n" >> /boot/config/plugins/dynamix/cpu_governor.cron
	else
		# Remove dynamix set governor cron file.
		rm -f /boot/config/plugins/dynamix/cpu_governor.cron
	fi

	if [ "$CPU_GOVERNOR" != "" ]; then
		set_governor "$CPU_GOVERNOR"

		if [ `turbo_mode` == "yes" ]; then
			if [ "$TURBO_BOOST" = "yes" ]; then
				if [ "`/usr/bin/cpufreq-info -d 2>/dev/null`" == "intel_pstate" ]; then
					/usr/bin/flock -x -w 1 /sys/devices/system/cpu/intel_pstate/no_turbo -c 'echo "0" > /sys/devices/system/cpu/intel_pstate/no_turbo' &>/dev/null
				elif [ "`/usr/bin/cpufreq-info -d 2>/dev/null`" == "intel_cpufreq" ]; then
					/usr/bin/flock -x -w 1 /sys/devices/system/cpu/intel_pstate/no_turbo -c 'echo "0" > /sys/devices/system/cpu/intel_pstate/no_turbo' &>/dev/null
				else
					/usr/bin/flock -x -w 1 /sys/devices/system/cpu/cpufreq/boost -c 'echo "1" > /sys/devices/system/cpu/cpufreq/boost' &>/dev/null
				fi
			else
				if [ "`/usr/bin/cpufreq-info -d 2>/dev/null`" == "intel_pstate" ]; then
					/usr/bin/flock -x -w 1 /sys/devices/system/cpu/intel_pstate/no_turbo -c 'echo "1" > /sys/devices/system/cpu/intel_pstate/no_turbo' &>/dev/null
				elif [ "`/usr/bin/cpufreq-info -d 2>/dev/null`" == "intel_cpufreq" ]; then
					/usr/bin/flock -x -w 1 /sys/devices/system/cpu/intel_pstate/no_turbo -c 'echo "1" > /sys/devices/system/cpu/intel_pstate/no_turbo' &>/dev/null
				else
					/usr/bin/flock -x -w 1 /sys/devices/system/cpu/cpufreq/boost -c 'echo "0" > /sys/devices/system/cpu/cpufreq/boost' &>/dev/null
				fi
			fi
		fi
	fi

	rm -f ${DOCROOT}/plugins/${plugin}/event/stopping_svcs
	IFS=","
	list=($KILL)
	for ((i=0; i<${#list[@]}; ++i)); do
		process=${list[$i]}
		echo "killall -eq -s SIGKILL ${process}" >> ${DOCROOT}/plugins/${plugin}/event/stopping_svcs
	done
	if [ -f ${DOCROOT}/plugins/${plugin}/event/stopping_svcs ]; then
		chmod +x ${DOCROOT}/plugins/${plugin}/event/stopping_svcs
	fi

	IFS=$OIFS

	remove_syslog

	if [ "$ARCHIVE_LOGS" = "yes" ]; then
		echo -e "\n\n#archive_logs_start\n${DOCROOT}/plugins/${plugin}/scripts/rc.tweaks save_syslog\n#archive_logs_end" >> /etc/rc.d/rc.local_shutdown
	fi

	# Reload dynamix crons.
	/usr/local/sbin/update_cron

	logger "Tweaks Applied" -t$PROG_NAME
}

flow_control() {
	flow="Off"
	avail="no"
	OIFS=$IFS
	IFS=","
	list=($ETHERNET_NICS)
	for ((i=0; i<${#list[@]}; ++i)); do
		nic=${list[$i]}
		value=`/usr/sbin/ethtool -a $nic 2>/dev/null | grep -i 'RX:' | /bin/awk '{print $2}'`
		if [ ! -z $value ]; then
			if [ "$value"  == "on" ]; then
				flow="On"
			fi
			avail="yes"
		fi
	done
	IFS=$OIFS

	if [ "$avail" = "yes"  ]; then
		echo $flow
	else
		echo $not_avail
	fi
}

tso_offload() {
	offload="Off"
	avail="no"
	OIFS=$IFS
	IFS=","
	list=($ETHERNET_NICS)
	for ((i=0; i<${#list[@]}; ++i)); do
		nic=${list[$i]}
		value=`/usr/sbin/ethtool -k $nic 2>/dev/null | grep -i 'tcp-segmentation-offload:' | /bin/awk '{print $2}'`
		if [ ! -z $value ]; then
			if [ "$value"  == "on" ]; then
				offload="On"
			fi
			avail="yes"
		fi
	done
	IFS=$OIFS

	if [ "$avail" = "yes"  ]; then
		echo $offload
	else
		echo $not_avail
	fi
}

rx_buffer() {
	rx=0
	avail="no"
	OIFS=$IFS
	IFS=","
	list=($ETHERNET_NICS)
	for ((i=0; i<${#list[@]}; ++i)); do
		nic=${list[$i]}
		value=`/usr/sbin/ethtool -g $nic 2>/dev/null | grep -i 'RX:' 2>/dev/null | tr -d '\n' | /bin/awk '{print $3}'`
		if [ $value > $rx ]; then
			rx=$value
			avail="yes"
		fi
	done
	IFS=$OIFS

	if [ "$avail" = "yes"  ]; then
		echo $rx
	else
		echo $no_buffer
	fi
}

tx_buffer() {
	tx=0
	avail="no"
	OIFS=$IFS
	IFS=","
	list=($ETHERNET_NICS)
	for ((i=0; i<${#list[@]}; ++i)); do
		nic=${list[$i]}
		value=`/usr/sbin/ethtool -g $nic 2>/dev/null | grep -i 'TX:' | tr -d '\n' | /bin/awk '{print $3}'`
		if [ $value > $tx ]; then
			tx=$value
			avail="yes"
		fi
	done
	IFS=$OIFS

	if [ "$avail" = "yes"  ]; then
		echo $tx
	else
		echo $no_buffer
	fi
}

vm_dirty() {
	sysctl vm.dirty_ratio
}

vm_background() {
	sysctl vm.dirty_background_ratio
}

current_user_watches() {
	find /proc/*/fd -lname anon_inode:inotify | cut -d/ -f3 | awk '{s+=$1} END {print s}'
}

max_user_watches() {
	sysctl fs.inotify.max_user_watches | /bin/awk '{print $3}'
}

cpu_freq_driver() {
	value=`/usr/bin/cpufreq-info -d 2>/dev/null`
	case "$value" in
		'acpi-cpufreq')
			echo "ACPI CPU Freq"
		;;
		'intel_pstate')
			echo "Intel Pstate"
		;;
		'intel_cpufreq')
			echo "Intel CPU Freq"
		;;
		'powernow_k8')
			echo "Powernow K8/K10"
		;;
		*)
			if [ "$value" != "" ]; then
				echo $value
			else
				echo "* no driver *"
			fi
	esac
}

cpu_governor() {
	value=`/usr/bin/cpufreq-info -p  | /bin/awk '{print $3}' 2>/dev/null`
	case "$value" in
		'ondemand')
			echo "On Demand"
		;;
		'performance')
			echo "Performance"
		;;
		'powersave')
			echo "Power Save"
		;;
		'conservative')
			echo "Conservative"
		;;
		'schedutil')
			echo "Schedutil"
		;;
		*)
			echo $value
	esac
}

set_governor() {
	cpus=`cat /proc/cpuinfo | grep processor | wc -l 2>/dev/null`
	for ((i=0; i<${cpus}; ++i)); do
		/usr/bin/cpufreq-set -c $i -g $1 &>/dev/null
	done
}

turbo_mode() {
	turbo_mode="no"
	value=`/usr/bin/cpufreq-info -d 2>/dev/null`
	case "$value" in
		'acpi-cpufreq')
			turbo_mode="yes"
		;;
			'intel_pstate')
				turbo_mode="yes"
		;;
			'intel_cpufreq')
				turbo_mode="yes"
	esac
	echo ${turbo_mode}
}

save_syslog()
{
	# capture the system diagnostics
	logger "Capture diagnostics to /boot/logs"
	echo "Capture diagnostics to /boot/logs"
	rm -f /boot/logs/*diagnostics*.zip
	/usr/local/sbin/diagnostics

	# If the LOG directory does not exist, make it!
	[ ${LOGSAVE} -ne "0" ] && [ ! -d ${LOGDIR} ] && mkdir -p ${LOGDIR}

	TS="%Y%m%d-%H%M%S"
	LOGDATE=`ls -l --time-style="+${TS}" /var/log/syslog | cut -d' ' -f6`
	LOGNAME="/boot/logs/syslog-${LOGDATE}.txt"

	# Save only the $LOGSAVE number of current files
	# save all logs if -1
	if [ ${LOGSAVE} -ne "-1" ] && [ ! -z "`ls -1t /boot/logs/syslog*.txt 2>/dev/null`" ]; then
		i=0
		ls -1t /boot/logs/syslog*.txt | while read SYSLOG
		do  ((i++))
			if [ $i -ge ${LOGSAVE} ]
			   then echo "Removing old syslog: ${SYSLOG}"
					rm -f ${SYSLOG}
			fi
		done
	fi

	echo "Saving current syslog: ${LOGNAME}"
	todos < /var/log/syslog > "${LOGNAME}"
	touch --reference=/var/log/syslog ${LOGNAME}
	chmod a-x ${LOGNAME}

	# Save latest syslog in a .zip archive for uploading
	# logger "zipping current syslog to /boot/logs/syslog.zip"
	# only zip a new syslog.txt if syslog newer then current .zip

	if [ ! -x /usr/bin/zip ]; then
		echo "zip not installed. Consider installing to automatically zip current syslog"
		return
	fi

	if [ /var/log/syslog -nt /boot/logs/syslog.zip ]; then
			cd /var/log
			# make a symlink to syslog.txt for windows viewing
			ln -s  syslog syslog.txt
			rm -f  /boot/logs/syslog.zip
			# -o (set .zip time to mtime of syslog)
			# -l (convert lf to crlf on the fly!)
			zip -o -l /boot/logs/syslog.zip syslog.txt
			rm -f  syslog.txt  # remove symlink
			chmod a-x /boot/logs/syslog.zip
	fi
}

remove_syslog() {
	# Remove archive_logs from rc.local_shutdown.
	if [ -f "/etc/rc.d/rc.local_shutdown" ]; then
		sed '/#archive_logs_start/,/#archive_logs_end/d' /etc/rc.d/rc.local_shutdown >> rc.local_shutdown.tmp
		printf %s "$(< rc.local_shutdown.tmp)" > /etc/rc.d/rc.local_shutdown
		rm -f rc.local_shutdown.tmp
	fi
}

get_nics() {
	# Get the installed nics
	nics=`/sbin/ifconfig | /usr/bin/grep 'eth[0-9]:' | /usr/bin/tr -d ':' | /bin/awk '{ print $1 }'`
	nics=${nics##*( )}
	echo -n $nics | tr ' ' ',' > /tmp/nics
}

# read our configuration.
plugin="tips.and.tweaks"
CONFIG="/boot/config/plugins/${plugin}/${plugin}.cfg"
source $CONFIG
if [ -z $START_TIME ]; then
	START_TIME="23:00"
fi
if [ -z $STOP_TIME ]; then
	STOP_TIME="05:00"
fi

PROG_NAME=${plugin}
DOCROOT=`grep -Po '^chdir = \K.*' /etc/php-fpm.d/www.conf`
if [ -z ${DOCROOT} ];then
	DOCROOT="/usr/local/emhttp"
fi

not_avail="N/A (Off)"
no_buffer="N/A"

# Set LOG directory
LOGDIR="/boot/logs/"

# Default nics if $ETHERTNET_NICS is defined
if [ -z ${ETHERNET_NICS} ]; then
	get_nics
	ETHERNET_NICS=`/usr/bin/cat /tmp/nics`
fi

# Be sure $LOGSAVE is defined.
if [ -z ${LOGSAVE} ]; then
	LOGSAVE="10"
fi

case "$1" in
	'apply')
		apply_tweaks
	;;
	'flow')
		flow_control
	;;
	'offload')
		tso_offload
	;;
	'rx_buffer')
		rx_buffer
	;;
	'tx_buffer')
		tx_buffer
	;;
	'vm_dirty')
		vm_dirty
	;;
	'vm_background')
		vm_background
	;;
	'current_user_watches')
		current_user_watches
	;;
	'max_user_watches')
		max_user_watches
	;;
	'cpu_freq_driver')
		cpu_freq_driver
	;;
	'cpu_governor')
		cpu_governor
	;;
	'set_governor')
		set_governor $2
	;;
	'turbo_mode')
		turbo_mode
	;;
		'save_syslog')
		save_syslog
	;;
		'remove_syslog')
		remove_syslog
	;;
		'get_nics')
		get_nics
		/usr/bin/cat /tmp/nics
	;;
	*)
		echo "usage $0 apply|flow|offload|rx_buffer|tx_buffer|vm_dirty|vm_background|current_user_watches|max_user_watches|cpu_freq_driver|cpu_governor|set_governor|turbo_mode|save_syslog|remove_syslog|get_nics"
esac
